package com.app.system.jpa;

import com.app.system.jpa.en.FieldType;
import com.app.system.jpa.en.Operator;
import com.app.system.utils.dataType.DateUtils;
import com.app.system.utils.WebUtils;
import com.app.system.utils.dataType.StringUtils;
import com.google.common.collect.Maps;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;

import javax.imageio.stream.FileImageInputStream;
import javax.servlet.http.HttpServletRequest;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.*;

/**
 * 组装查询条件
 */
public class Wrapper {

    private static final Logger logger = LoggerFactory.getLogger(Wrapper.class);

    //重复查询语句处理
    StringBuffer countQuery = new StringBuffer("");

    //拼接语句
    StringBuffer query_select = new StringBuffer();//select 【* from UserInfo u】 where u.id = :id group by u.id order by u.id
    StringBuffer query_where = new StringBuffer();//select * from UserInfo u where 【u.id = :id】 group by u.id order by u.id
    StringBuffer query_other = new StringBuffer();//select * from UserInfo u where u.id = :id 【group by u.id  ... 】 order by u.id
    StringBuffer query_orderBy = new StringBuffer();//select * from UserInfo u where u.id = :id group by u.id 【order by u.id】

    //封装接收的参数
    Map<String, Object> params = Maps.newLinkedHashMap();

    private String param_prefix = "search_";//查询参数前缀
    private String page_prefix = "_";//分页参数前缀
    private String whereKey = "where";//查询条件关键字

    private PageBean pageBean = new PageBean();

    /**
     * @param query_select
     * @param query_orderBy
     */
    public Wrapper(StringBuffer query_select, StringBuffer query_orderBy) {
        this.query_select.append(" select ").append(query_select);
        this.countQuery.append("count(1)");
        this.query_orderBy.append(" order by ").append(query_orderBy);
    }

    /**
     * @param query_select
     * @param countQuery
     * @param query_orderBy
     */
    public Wrapper(StringBuffer query_select, StringBuffer countQuery, StringBuffer query_orderBy) {
        this.query_select.append(" select ").append(query_select);
        if (countQuery == null || countQuery.length() == 0) {
            this.countQuery.append("count(1)");
        } else {
            this.countQuery.append(countQuery);
        }
        this.query_orderBy.append(" order by ").append(query_orderBy);
    }

    /**
     * 查询参初始化
     *
     * @param pageBean
     * @param query_select
     * @param countQuery
     * @param query_orderBy
     */
    public Wrapper(PageBean pageBean, StringBuffer query_select, String countQuery, StringBuffer query_orderBy) {
        this.pageBean = pageBean;
        this.query_select.append(" select ").append(query_select);
        if (countQuery == null || countQuery.isEmpty()) {
            this.countQuery.append("count(1)");
        } else {
            this.countQuery.append(countQuery);
        }
        this.query_orderBy.append(" order by ").append(query_orderBy);
    }

    /**
     * 查询项条件自动封装
     * 列表查询项自动初始化
     */
    public Wrapper initSearchParams() {

        HttpServletRequest request = WebUtils.getRequest();
        Enumeration<String> enumeration = request.getParameterNames();
        //封装查询参数及分页参数数据，不执行其他操作
        while (enumeration.hasMoreElements()) {
            String element = enumeration.nextElement();
            String value = request.getParameter(element);
            if (value == null || value.isEmpty()) {
                continue;
            }
            if (element.startsWith(param_prefix)) {
                String[] array = element.split("_");//search_eq_string_id
                if (array.length != 4) {
                    continue;
                }
                //运算符
                Operator operator = Operator.valueOf(array[1].toUpperCase());
                //数据类型
                FieldType fieldType = FieldType.valueOf(array[2].toUpperCase());
                //字段名称
                String name = array[3];
                //数值
                Object targetValue = getFieldTypeValue(fieldType, value);
                //存储查询参数
                addParam(operator, name, targetValue);
            } else if (element.startsWith(page_prefix)) {
                if ("_pageNum".equals(element)) {//页码
                    pageBean.setPageNum(Integer.valueOf(String.valueOf(value)));
                } else if ("_pageSize".equals(element)) {//每页数量
                    pageBean.setPageSize(Integer.valueOf(String.valueOf(value)));
                } else if ("_orderField".equals(element)) {//排序字段
                    pageBean.setOrderField(String.valueOf(value));
                } else if ("_orderType".equals(element)) {//排序方式
                    pageBean.setOrderType(String.valueOf(value));
                }
            }
        }
        return this;
    }

    /**
     * 添加查询条件
     *
     * @param operator
     * @param name
     * @param value
     * @return
     */
    private Wrapper addParam(Operator operator, String name, Object value) {
        switch (operator) {
            case EQ:
                this.andEq(name, value);
                break;
            case NEWEQ:
                this.andNewEq(name, value);
                break;
            case LIKE:
                this.andLike(name, String.valueOf(value));
                break;
            case NEWLIKE:
                this.andNewLike(name, String.valueOf(value));
                break;
            case NE:
                this.andNe(name, value);
                break;
            case GT:
                this.andGt(name, value);
                break;
            case GE:
                this.andGe(name, value);
                break;
            case LT:
                this.andLt(name, value);
                break;
            case LE:
                this.andLe(name, value);
                break;
            default:
                break;
        }
        return this;
    }

    /**
     * 获取相应的类型的数值
     *
     * @param fieldType
     * @param value
     * @return
     */
    private Object getFieldTypeValue(FieldType fieldType, String value) {
        Object target = null;
        try {
            switch (fieldType) {
                case STRING:
                    target = value;
                    break;
                case INTEGER:
                    target = Integer.valueOf(value);
                    break;
                case BIGDECIMAL:
                    target = new BigDecimal(value);
                    break;
                case DATE:
                    target = DateUtils.stringToDateFormat(value, "yyyy-MM-dd");
                    break;
                case DATEFORMAT:
                    target = DateUtils.stringToDateFormat(value, "yyyy-MM-dd HH:mm:ss");
                    break;
                default:
                    break;
            }
        } catch (Exception e) {
            logger.warn("fieldType=" + fieldType + " : " + e.getMessage());
        }
        return target;
    }

    private String getParamAlias(String name) {
        if (name == null || name.isEmpty()) {
            return "";
        }
        name = name.replace(".", "");
        return name;
    }


    public Wrapper andEq(String name, Object value) {
        String alias = this.getParamAlias(name);
        if (query_where.indexOf(whereKey) < 0) {
            query_where.append(" where ");
        } else {
            query_where.append(" and ");
        }
        query_where.append(name).append(" = :" + alias);
        params.put(alias, value);
        return this;
    }

    public Wrapper andNewEq(String name, Object value) {
        String alias = this.getParamAlias(name);
        query_where.append(" and ");
        query_where.append(name).append(" = :" + alias);
        params.put(alias, value);
        return this;
    }


    public Wrapper orEq(String name, Object value) {
        String alias = this.getParamAlias(name);
        if (query_where.indexOf(whereKey) < 0) {
            query_where.append(" where ");
        } else {
            query_where.append(" or ");
        }
        query_where.append(name).append(" = :" + alias);
        params.put(alias, value);
        return this;
    }


    public Wrapper andNe(String name, Object value) {
        String alias = this.getParamAlias(name);
        if (query_where.indexOf(whereKey) < 0) {
            query_where.append(" where ");
        } else {
            query_where.append(" and ");
        }
        query_where.append(name).append(" != :" + alias);
        params.put(alias, value);
        return this;
    }


    public Wrapper orNe(String name, Object value) {
        String alias = this.getParamAlias(name);
        if (query_where.indexOf(whereKey) < 0) {
            query_where.append(" where ");
        } else {
            query_where.append(" or ");
        }
        query_where.append(name).append(" != :" + alias);
        params.put(alias, value);
        return this;
    }


    public Wrapper andGt(String name, Object value) {

        String alias = this.getParamAlias(name);
        if (query_where.indexOf(whereKey) < 0) {
            query_where.append(" where ");
        } else {
            query_where.append(" and ");
        }
        query_where.append(name).append(" > :" + alias);
        params.put(alias, value);
        return this;
    }


    public Wrapper orGt(String name, Object value) {

        String alias = this.getParamAlias(name);
        if (query_where.indexOf(whereKey) < 0) {
            query_where.append(" where ");
        } else {
            query_where.append(" or ");
        }
        query_where.append(name).append(" > :" + alias);
        params.put(alias, value);
        return this;
    }


    public Wrapper andGe(String name, Object value) {
        String alias = this.getParamAlias(name);
        if (query_where.indexOf(whereKey) < 0) {
            query_where.append(" where ");
        } else {
            query_where.append(" and ");
        }
        query_where.append(name).append(" >= :" + alias);
        params.put(alias, value);
        return this;
    }


    public Wrapper orGe(String name, Object value) {
        String alias = this.getParamAlias(name);
        if (query_where.indexOf(whereKey) < 0) {
            query_where.append(" where ");
        } else {
            query_where.append(" or ");
        }
        query_where.append(name).append(" >= :" + alias);
        params.put(alias, value);
        return this;
    }


    public Wrapper andLt(String name, Object value) {
        String alias = this.getParamAlias(name);
        if (query_where.indexOf(whereKey) < 0) {
            query_where.append(" where ");
        } else {
            query_where.append(" and ");
        }
        query_where.append(name).append(" < :" + alias);
        params.put(alias, value);
        return this;
    }


    public Wrapper orLt(String name, Object value) {
        String alias = this.getParamAlias(name);
        if (query_where.indexOf(whereKey) < 0) {
            query_where.append(" where ");
        } else {
            query_where.append(" or ");
        }
        query_where.append(name).append(" < :" + alias);
        params.put(alias, value);
        return this;
    }


    public Wrapper andLe(String name, Object value) {
        String alias = this.getParamAlias(name);
        if (query_where.indexOf(whereKey) < 0) {
            query_where.append(" where ");
        } else {
            query_where.append(" and ");
        }
        query_where.append(name).append(" <= :" + alias);
        params.put(alias, value);
        return this;
    }


    public Wrapper orLe(String name, Object value) {
        String alias = this.getParamAlias(name);
        if (query_where.indexOf(whereKey) < 0) {
            query_where.append(" where ");
        } else {
            query_where.append(" or ");
        }
        query_where.append(name).append(" <= :" + alias);
        params.put(alias, value);
        return this;
    }

    public Wrapper andLike(String name, String value) {
        String alias = this.getParamAlias(name);
        if (query_where.indexOf(whereKey) < 0) {
            query_where.append(" where ");
        } else {
            query_where.append(" and ");
        }
        query_where.append(name).append(" like :" + alias);
        params.put(alias, "%" + value + "%");
        return this;
    }

    public Wrapper andNewLike(String name, String value) {
        String alias = this.getParamAlias(name);
        query_where.append(" and ");
        query_where.append(name).append(" like :" + alias);
        params.put(alias, "%" + value + "%");
        return this;
    }


    public Wrapper orLike(String name, String value) {
        String alias = this.getParamAlias(name);
        if (query_where.indexOf(whereKey) < 0) {
            query_where.append(" where ");
        } else {
            query_where.append(" or ");
        }
        query_where.append(name).append(" like :" + alias);
        params.put(alias, "%" + value + "%");
        return this;
    }


    public Wrapper andNotLike(String name, String value) {
        String alias = this.getParamAlias(name);
        if (query_where.indexOf(whereKey) < 0) {
            query_where.append(" where ");
        } else {
            query_where.append(" and ");
        }
        query_where.append(name).append(" not like :" + alias);
        params.put(alias, "%" + value + "%");
        return this;
    }


    public Wrapper orNotLike(String name, String value) {
        String alias = this.getParamAlias(name);
        if (query_where.indexOf(whereKey) < 0) {
            query_where.append(" where ");
        } else {
            query_where.append(" or ");
        }
        query_where.append(name).append(" not like :" + alias);
        params.put(alias, "%" + value + "%");
        return this;
    }


    public Wrapper andIsNull(String name) {
        if (query_where.indexOf(whereKey) < 0) {
            query_where.append(" where ");
        } else {
            query_where.append(" and ");
        }
        query_where.append(name).append(" is null");
        return this;
    }


    public Wrapper orIsNull(String name) {
        if (query_where.indexOf(whereKey) < 0) {
            query_where.append(" where ");
        } else {
            query_where.append(" or ");
        }
        query_where.append(name).append(" is null");
        return this;
    }


    public Wrapper andNotNull(String name) {
        if (query_where.indexOf(whereKey) < 0) {
            query_where.append(" where ");
        } else {
            query_where.append(" and ");
        }
        query_where.append(name).append(" is not null");
        return this;
    }


    public Wrapper orNotNull(String name) {
        if (query_where.indexOf(whereKey) < 0) {
            query_where.append(" where ");
        } else {
            query_where.append(" or ");
        }
        query_where.append(name).append(" is not null");
        return this;
    }


    public Wrapper andIn(String name, List<?> values) {
        String alias = this.getParamAlias(name);
        if (query_where.indexOf(whereKey) < 0) {
            query_where.append(" where ");
        } else {
            query_where.append(" and ");
        }
        query_where.append(name).append(" in (:" + alias + ") ");
        params.put(alias, values);
        return this;
    }


    public Wrapper orIn(String name, List<?> values) {
        String alias = this.getParamAlias(name);
        if (query_where.indexOf(whereKey) < 0) {
            query_where.append(" where ");
        } else {
            query_where.append(" or ");
        }
        query_where.append(name).append(" in (:" + alias + ") ");
        params.put(alias, values);
        return this;
    }


    public Wrapper andNotIn(String name, List<?> values) {
        String alias = this.getParamAlias(name);
        if (query_where.indexOf(whereKey) < 0) {
            query_where.append(" where ");
        } else {
            query_where.append(" and ");
        }
        query_where.append(name).append(" not in (:" + alias + ") ");
        params.put(alias, values);
        return this;
    }


    public Wrapper orNotIn(String name, List<?> values) {
        String alias = this.getParamAlias(name);
        if (query_where.indexOf(whereKey) < 0) {
            query_where.append(" where ");
        } else {
            query_where.append(" or ");
        }
        query_where.append(name).append(" not in (:" + alias + ") ");
        params.put(alias, values);
        return this;
    }


    public Wrapper andBetween(String name, Object start, Object end) {
        String alias = this.getParamAlias(name);
        String startName = alias + "Start";
        String endName = alias + "End";
        if (query_where.indexOf(whereKey) < 0) {
            query_where.append(" where ");
        } else {
            query_where.append(" and ");
        }
        query_where.append(name).append(" between :" + startName + " and :" + endName + " ");
        params.put(startName, start);
        params.put(endName, end);
        return this;
    }


    public Wrapper orBetween(String name, Object start, Object end) {
        String alias = this.getParamAlias(name);
        String startName = alias + "Start";
        String endName = alias + "End";
        if (query_where.indexOf(whereKey) < 0) {
            query_where.append(" where ");
        } else {
            query_where.append(" or ");
        }
        query_where.append(name).append(" between :" + startName + " and :" + endName + " ");
        params.put(startName, start);
        params.put(endName, end);
        return this;
    }


    public Wrapper andNotBetween(String name, Object start, Object end) {
        String alias = this.getParamAlias(name);
        String startName = alias + "Start";
        String endName = alias + "End";
        if (query_where.indexOf(whereKey) < 0) {
            query_where.append(" where ");
        } else {
            query_where.append(" and ");
        }
        query_where.append(name).append(" not between :" + startName + " and :" + endName + " ");
        params.put(startName, start);
        params.put(endName, end);
        return this;
    }


    public Wrapper orNotBetween(String name, Object start, Object end) {
        String alias = this.getParamAlias(name);
        String startName = alias + "Start";
        String endName = alias + "End";
        if (query_where.indexOf(whereKey) < 0) {
            query_where.append(" where ");
        } else {
            query_where.append(" or ");
        }
        query_where.append(name).append(" not between :" + startName + " and :" + endName + " ");
        params.put(startName, start);
        params.put(endName, end);
        return this;
    }

    public Wrapper queryOther(StringBuffer query_other) {
        this.query_other.append(query_other);
        return this;
    }

//    //排序赋值
//    public Wrapper orderBy(String query_orderBy) {
//        if (this.query_orderBy.length() == 0) {
//            this.query_orderBy.append(" order by ").append(query_orderBy);
//        } else if (pageBean.getOrderField() != null && !pageBean.getOrderField().isEmpty()) {//页面自定义排序
//            this.query_orderBy.append(" order by ").append(pageBean.getOrderField()).append(" ").append(pageBean.getOrderType());
//        }
//        return this;
//    }

    public Map<String, Object> getParams() {
        return params;
    }

    public String getQuery() {
        StringBuffer query = new StringBuffer("");
        if (pageBean.getOrderField() != null && !pageBean.getOrderField().isEmpty()) {
            query_orderBy = new StringBuffer("");
            query_orderBy.append(" order by ").append(pageBean.getOrderField()).append(" ").append(pageBean.getOrderType());
        }
        query.append(query_select).append(query_where).append(query_other).append(query_orderBy);
        return query.toString();
    }

    public String getCountQuery() {
        return countQuery.toString();
    }

    public PageBean getPageBean() {
        return this.pageBean;
    }

    /**
     * 获取上传的文件
     *
     * @param request
     * @param parameterName
     * @return
     * @throws IOException
     */
    public static byte[] uploadFile(HttpServletRequest request, String parameterName) throws IOException {
        byte[] data = null;
        MultipartHttpServletRequest multipartRequest = null;

        try {
            multipartRequest = (MultipartHttpServletRequest) request;
        } catch (ClassCastException var5) {
            return data;
        }

        MultipartFile multipartFile = multipartRequest.getFile(parameterName);
        if (StringUtils.isNotEmpty(multipartFile.getOriginalFilename())) {
            data = multipartFile.getBytes();
        }

        return data;
    }
}
